Ovladajte TypeScript .d.ts datotekama za tipsku sigurnost i automatsko dovršavanje za sve JS biblioteke. Naučite koristiti @types i stvarati vlastite definicije.
Otključavanje JavaScript ekosustava: Dubinski pogled na datoteke deklaracija u TypeScriptu
TypeScript je revolucionizirao moderni web razvoj donoseći statičko tipiziranje u dinamičan svijet JavaScripta. Ova tipsko-sigurnost pruža nevjerojatne prednosti: hvatanje grešaka u vrijeme kompilacije, omogućavanje moćnog automatskog dovršavanja u editoru i značajno lakše održavanje velikih kodnih baza. Međutim, velik izazov nastaje kada želimo koristiti ogroman ekosustav postojećih JavaScript biblioteka – od kojih većina nije napisana u TypeScriptu. Kako naš strogo tipizirani TypeScript kod razumije strukture, funkcije i varijable iz netipizirane JavaScript biblioteke?
Odgovor leži u TypeScript datotekama deklaracija. Ove datoteke, prepoznatljive po ekstenziji .d.ts, ključni su most između TypeScript i JavaScript svijeta. Djeluju kao nacrt ili API ugovor, opisujući tipove biblioteke treće strane bez sadržavanja njezine stvarne implementacije. U ovom sveobuhvatnom vodiču, istražiti ćemo sve što trebate znati kako biste samopouzdano upravljali definicijama tipova za bilo koju JavaScript biblioteku u vašim TypeScript projektima.
Što su točno datoteke deklaracija u TypeScriptu?
Zamislite da ste unajmili izvođača koji govori samo drugačijim jezikom. Da biste učinkovito surađivali s njime, trebali biste prevoditelja ili detaljan skup uputa na jeziku koji oboje razumijete. Datoteka deklaracije služi upravo toj svrsi za TypeScript kompajler (izvođača).
.d.ts datoteka sadrži samo informacije o tipovima. Uključuje:
- Potpise za funkcije i metode (tipovi parametara, povratni tipovi).
- Definicije varijabli i njihovih tipova.
- Sučelja i aliase tipova za složene objekte.
- Definicije klasa, uključujući njihova svojstva i metode.
- Strukture prostora imena i modula.
Ključno je da ove datoteke ne sadrže nikakav izvršni kod. One su isključivo za statičku analizu. Kada uvezete JavaScript biblioteku poput Lodasha u svoj TypeScript projekt, kompajler traži odgovarajuću datoteku deklaracija. Ako je pronađe, može validirati vaš kod, pružiti inteligentno automatsko dovršavanje i osigurati da ispravno koristite biblioteku. Ako je ne pronađe, prikazat će grešku poput: Could not find a declaration file for module 'lodash'.
Zašto su datoteke deklaracija neizostavne za profesionalni razvoj
Korištenje JavaScript biblioteka bez odgovarajućih definicija tipova u TypeScript projektu potkopava sam razlog korištenja TypeScripta. Razmotrimo jednostavan scenarij koristeći popularnu pomoćnu biblioteku Lodash.
Svijet bez definicija tipova
Bez datoteke deklaracija, TypeScript nema pojma što je lodash niti što sadrži. Kako bi se kod uopće kompilirao, mogli biste biti u iskušenju da upotrijebite brzo rješenje poput ovog:
const _: any = require('lodash');
const users = [{ 'user': 'barney' }, { 'user': 'fred' }];
// Automatsko dovršavanje? Nema pomoći ovdje.
// Tipsko provjeravanje? Ne. Je li 'username' ispravan property?
// Kompajler to dopušta, ali se može dogoditi greška u runtimeu.
_.find(users, { username: 'fred' });
U ovom slučaju, varijabla _ je tipa any. Ovo efektivno govori TypeScriptu: "Nemoj provjeravati ništa vezano uz ovu varijablu." Gube se sve prednosti: nema automatskog dovršavanja, nema tipskog provjeravanja argumenata i nema sigurnosti u povratni tip. Ovo je leglo grešaka u runtimeu.
Svijet s definicijama tipova
Sada pogledajmo što se događa kada osiguramo potrebnu datoteku deklaracija. Nakon instalacije tipova (o čemu ćemo govoriti dalje), iskustvo je transformirano:
import _ from 'lodash';
interface User {
user: string;
active?: boolean;
}
const users: User[] = [{ 'user': 'barney' }, { 'user': 'fred' }];
// 1. Editor pruža automatsko dovršavanje za 'find' i druge lodash funkcije.
// 2. Pomicanjem pokazivača iznad 'find' prikazuje se puni potpis i dokumentacija.
// 3. TypeScript vidi da je `users` niz `User` objekata.
// 4. TypeScript zna da predikat za `find` na `User[]` treba uključivati `user` ili `active`.
// ISPRAVNO: TypeScript je zadovoljan.
const fred = _.find(users, { user: 'fred' });
// GREŠKA: TypeScript hvata grešku!
// Property 'username' does not exist on type 'User'.
Razlika je drastična. Dobivamo punu tipsku sigurnost, superiorno iskustvo razvoja kroz alate i dramatično smanjenje potencijalnih grešaka. Ovo je profesionalni standard za rad s TypeScriptom.
Hijerarhija pronalaženja definicija tipova
Dakle, kako dobiti ove čarobne .d.ts datoteke za vaše omiljene biblioteke? Postoji dobro uspostavljen proces koji pokriva veliku većinu scenarija.
Korak 1: Provjerite jesu li tipove sami učitali u biblioteku
Najbolji scenarij je kada je biblioteka napisana u TypeScriptu ili njezini održavatelji pružaju službene datoteke deklaracija unutar istog paketa. Ovo je sve češće za moderne, dobro održavane projekte.
Kako provjeriti:
- Instalirajte biblioteku kao i obično:
npm install axios - Pogledajte u mapu biblioteke u
node_modules/axios. Vidite li neke.d.tsdatoteke? - Provjerite
package.jsondatoteku biblioteke za polje"types"ili"typings". Ovo polje izravno pokazuje na glavnu datoteku deklaracija. Na primjer,package.jsonAxiosa sadrži:"types": "index.d.ts".
Ako su ti uvjeti zadovoljeni, gotovi ste! TypeScript će automatski pronaći i koristiti ove učitane tipove. Nije potrebno daljnje djelovanje.
Korak 2: Projekt DefinitelyTyped (@types)
Za tisuće JavaScript biblioteka koje ne učitavaju vlastite tipove, globalna TypeScript zajednica stvorila je nevjerojatan resurs: DefinitelyTyped.
DefinitelyTyped je centralizirano, zajednicom upravljano spremište na GitHubu koje sadrži visokokvalitetne datoteke deklaracija za ogroman broj JavaScript paketa. Ove definicije objavljuju se na npm registru pod @types opsegom.
Kako koristiti:
Ako biblioteka poput lodash ne učitava vlastite tipove, jednostavno instalirajte njezin odgovarajući @types paket kao razvojnu ovisnost:
npm install --save-dev @types/lodash
Konvencija imenovanja je jednostavna i predvidljiva: za paket nazvan naziv-paketa, njegovi tipovi će gotovo uvijek biti na @types/naziv-paketa. Možete pretraživati dostupne tipove na npm web stranici ili izravno na DefinitelyTyped spremištu.
Zašto --save-dev? Datoteke deklaracija potrebne su samo tijekom razvoja i kompilacije. Ne sadrže nikakav kod u runtimeu, stoga ne bi trebale biti uključene u vaš konačni proizvodni paket. Njihova instalacija kao devDependency osigurava to odvajanje.
Korak 3: Kada tipovi ne postoje - Pisati vlastite
Što ako koristite stariju, nišnu ili internu privatnu biblioteku koja ne učitava tipove i nije na DefinitelyTyped? U tom slučaju, morate se primiti posla i stvoriti vlastitu datoteku deklaracija. Iako ovo može zvučati zastrašujuće, možete početi jednostavno i dodavati više detalja prema potrebi.
Brzo rješenje: Skraćena deklaracija ambijentalnog modula
Ponekad vam je samo potrebno da vaš projekt uspješno kompilira bez grešaka dok ne smislite pravu strategiju tipiziranja. Možete stvoriti datoteku u svom projektu (npr. declarations.d.ts ili types/global.d.ts) i dodati skraćenu deklaraciju:
// u .d.ts datoteci
declare module 'neka-netipizirana-biblioteka';
Ovo govori TypeScriptu: "Vjeruj mi, postoji modul nazvan 'neka-netipizirana-biblioteka'. Samo tretuj sve što se uveze iz njega kao tip any." Ovo utišava grešku kompajlera, ali kao što smo raspravljali, žrtvuje svu tipsku sigurnost za tu biblioteku. To je privremeni flaster, a ne dugoročno rješenje.
Stvaranje osnovne datoteke deklaracija po mjeri
Bolji pristup je početi definiranjem tipova za dijelove biblioteke koje zapravo koristite. Recimo da imamo jednostavnu biblioteku pod nazivom `string-utils` koja izvozi samo jednu funkciju.
// U node_modules/string-utils/index.js
module.exports.capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
Možemo stvoriti string-utils.d.ts datoteku u namjenskoj `types` mapi u korijenu našeg projekta.
// U my-project/types/string-utils.d.ts
declare module 'string-utils' {
export function capitalize(str: string): string;
// Ovdje možete dodati definicije drugih funkcija kako ih koristite
// export function slugify(str: string): string;
}
Sada moramo reći TypeScriptu gdje da pronađe naše prilagođene definicije tipova. To radimo u tsconfig.json:
{
"compilerOptions": {
// ... druge opcije
"baseUrl": ".",
"paths": {
"*": ["types/*"]
}
}
}
S ovim postavkama, kada import { capitalize } from 'string-utils', TypeScript će pronaći vašu prilagođenu datoteku deklaracija i pružiti tipsku sigurnost koju ste definirali. Možete postupno graditi ovu datoteku kako koristite više značajki biblioteke.
Dublje uranjanje: Kreiranje datoteka deklaracija
Istražimo neke naprednije koncepte koje ćete susresti prilikom pisanja ili čitanja datoteka deklaracija.
Deklariranje različitih vrsta izvoza
JavaScript moduli mogu izvoziti stvari na različite načine. Vaša datoteka deklaracija mora odgovarati strukturi izvoza biblioteke.
- Imenovane izvoze: Ovo je najčešće. Vidjeli smo to gore s
export function capitalize(...). Također možete izvoziti konstante, sučelja i klase. - Zadani izvoz: Za biblioteke koje koriste
export default. - UMD Globalne varijable: Za starije biblioteke dizajnirane za rad u preglednicima putem
<script>oznake, često se povezuju s globalnimwindowobjektom. Možete deklarirati ove globalne varijable. export =iimport = require(): Ova sintaksa je za starije CommonJS module koji koristemodule.exports = .... Na primjer, ako biblioteka radimodule.exports = mojaKlasa;.
declare module 'moja-lib' {
export const verzija: string;
export interface Opcije { retries: number; }
export function doSomething(options: Opcije): Promise
declare module 'moja-zadana-lib' {
// Za zadani izvoz funkcije
export default function mojaSjajnaFunkcija(): void;
// Za zadani izvoz objekta
// const mojaLib = { name: 'lib', version: '1.0' };
// export default mojaLib;
}
// Deklarira globalnu varijablu '$' određenog tipa
declare var $: JQueryStatic;
// u my-class.d.ts
declare class MojaKlasa { constructor(name: string); }
export = MojaKlasa;
// u vašem app.ts
import MojaKlasa = require('my-class');
const instanca = new MojaKlasa('test');
Iako je manje uobičajeno s modernim ES modulima, ovo je ključno za kompatibilnost s mnogim starijim, ali još uvijek široko korištenim Node.js paketima.
Augmentacija modula: Proširenje postojećih tipova
Jedna od najmoćnijih značajki je augmentacija modula (također poznata kao spajanje deklaracija). Ovo vam omogućuje dodavanje svojstava postojećim sučeljima definiranim u datoteci deklaracija druge biblioteke. Ovo je izuzetno korisno za biblioteke s arhitekturom dodataka, poput Expressa ili Fastifyja.
Zamislite da koristite middleware u Expressu koji dodaje user svojstvo `Request` objektu. Bez augmentacije, TypeScript bi prigovorio da user ne postoji na Request.
Evo kako možete obavijestiti TypeScript o ovom novom svojstvu:
// u vašoj datoteci types/express.d.ts
// Moramo uvesti originalni tip kako bismo ga augmentirali
import { UserProfile } from './auth'; // Pretpostavljajući da imate UserProfile tip
// Recite TypeScriptu da augmentiramo 'express-serve-static-core' modul
declare module 'express-serve-static-core' {
// Ciljajte 'Request' sučelje unutar tog modula
interface Request {
// Dodajte naše prilagođeno svojstvo
user?: UserProfile;
}
}
Sada, diljem vaše aplikacije, Expressov `Request` objekt će biti ispravno tipiziran s opcijskim `user` svojstvom, a dobit ćete punu tipsku sigurnost i automatsko dovršavanje.
Direktive s trostrukim kosim crtama
Ponekad možete vidjeti komentare na vrhu .d.ts datoteka koji počinju s tri kose crte (///). Ovo su direktive s trostrukim kosim crtama, koje djeluju kao upute kompajleru.
/// <reference types="..." />: Ovo je najčešće. Eksplicitno uključuje definicije tipova drugog paketa kao ovisnost. Na primjer, tipovi za WebdriverIO dodatak mogu uključivati/// <reference types="webdriverio" />jer njihovi vlastiti tipovi ovise o ključnim WebdriverIO tipovima./// <reference path="..." />: Ovo se koristi za deklariranje ovisnosti o drugoj datoteci unutar istog projekta. To je stariji sintaksni oblik, uglavnom zamijenjen ES modul uvozima.
Najbolje prakse za upravljanje datotekama deklaracija
- Preferirajte učitane tipove: Pri odabiru između biblioteka, favorizirajte one koje su napisane u TypeScriptu ili učitavaju vlastite službene definicije tipova. To signalizira predanost TypeScript ekosustavu.
- Držite
@typesudevDependencies: Uvijek instalirajte@typespakete s--save-devili-D. Nisu potrebni za vaš proizvodni kod. - Usklađivanje verzija: Čest izvor grešaka je nesklad između verzije biblioteke i njezine
@typesverzije. Glavno povećanje verzije u biblioteci (npr. s v2 na v3) vjerojatno će imati lomljive promjene u svom API-ju, što se mora odraziti u@typespaketu. Pokušajte ih držati usklađenima. - Koristite
tsconfig.jsonza kontrolu:typeRootsitypesopcije kompajlera u vašemtsconfig.jsonmogu vam dati finu kontrolu nad time gdje TypeScript traži datoteke deklaracija.typeRootsgovori kompajleru koje mape da provjeri (prema zadanim postavkama, to je./node_modules/@types), atypesvam omogućuje da eksplicitno navedete koje tipove paketa treba uključiti. - Doprinesite natrag: Ako napišete sveobuhvatnu datoteku deklaracija za biblioteku koja je nema, razmislite o doprinosu projektu DefinitelyTyped. Ovo je fantastičan način da se vrati globalnoj zajednici programera i pomogne tisućama drugih.
Zaključak: Nepjevani heroji tipsko-sigurnosti
TypeScript datoteke deklaracija su nepjevani heroji koji omogućuju besprijekornu integraciju dinamičnog, raširenog svijeta JavaScripta u robusno, tipsko-sigurno razvojno okruženje. One su ključna veza koja osnažuje naše alate, sprječava nebrojene greške i čini naše kodne baze otpornijima i samoj dokumentirajućima.
Razumijevanjem kako pronaći, koristiti, pa čak i stvoriti vlastite .d.ts datoteke, ne samo da popravljate grešku kompajlera—vi podižete cijeli svoj razvojni tijek rada. Otključavate puni potencijal kako TypeScripta tako i bogatog ekosustava JavaScript biblioteka, stvarajući snažnu sinergiju koja rezultira boljim, pouzdanijim softverom za globalnu publiku.